###############################################################################
#                                                                             #
#    This file is part of the "ssbot" Python module.                          #
#    It is distributed under the MIT License. See LICENSE.txt for details.    #
#                                                                             #
###############################################################################


import multiprocessing
import os
import os.path
import Queue
import sys
import threading
import time

from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler

import steps


class CommandListener(object):
    class RpcRequestHandler(SimpleXMLRPCRequestHandler):
        rpc_paths = ('/RPC2',)

    class Method(object):
        def __init__(self, step_queue, result_queue):
            self.step_queue = step_queue
            self.result_queue = result_queue

        def run_step(self, step_info, path):
            self.step_queue.put((step_info, path))
            result = self.result_queue.get(block=True)
            return result

        def mkdir(self, dir_name):
            if os.path.exists(dir_name):
                return True
            os.mkdir(dir_name)
            return True

        def path_exists(self, path):
            return os.path.exists(path)

        def write_to_file(self, content, file_name):
            abs_file_path = os.path.abspath(file_name)
            success = False
            with open(file_name, 'w') as f:
                f.write(content)
                success = True
            if success:
                return abs_file_path
            else:
                return None

    def __init__(self, port, step_queue, result_queue):
        self.port = port
        self.step_queue = step_queue
        self.result_queue = result_queue

    def __call__(self):
        server = SimpleXMLRPCServer(
            ('', self.port), requestHandler=CommandListener.RpcRequestHandler,
            allow_none=True)
        server.register_instance(
            CommandListener.Method(self.step_queue, self.result_queue))
        server.serve_forever()

class BuildSlave(object):
    def __init__(self, port):
        self.port = port
        self.step_queue = multiprocessing.Queue()
        self.result_queue = multiprocessing.Queue()
        self.command_listener_process = multiprocessing.Process(
            target=CommandListener(port, self.step_queue, self.result_queue))
        self.exit_lock = threading.Lock()
        self.exit_lock.acquire(True)

    def start(self):
        self.command_listener_process.start()
        while True:
            try:
                step_info, path = self.step_queue.get(block=False)
                step = steps.Step(step_info['name'],
                                  step_info['cmd'],
                                  step_info['cwd'],
                                  step_info['deps'],
                                  step_info['timeout'])
                result = step.run(path)
                self.result_queue.put(result)
            except Queue.Empty:
                time.sleep(2)
            if self.exit_lock.acquire(False):
                break

    def stop(self):
        self.exit_lock.release()
        self.command_listener_process.terminate()
